
#include "tcpecho.h"
#include "lwip/opt.h"

#include "lwip/sys.h"

#include "lwip/api.h"
#include "lwip/sockets.h"



#define PORT 5001
#define RECV_DATA   (1024)

// 线程函数
static void tcpecho_thread(void *arg)
{
    int sock = -1,connected; //
    char *recv_data; // 接收数据指针 
    struct sockaddr_in server_addr,client_addr; //服务器IP地址，客户端IP地址
    socklen_t sin_size; // 
    int recv_data_len; //接收数据长度
    recv_data = (char *)pvPortMalloc(RECV_DATA); //分配内存
    // 判断是否成功分配到内存
    if(recv_data == NULL)
    {
        printf("NO menory \n");
        goto __exit;
    }
    sock = socket(AF_INET,SOCK_STREAM,0);// 向内核申请套接字
    // 判断是否成功申请到套接字 ，失败返回-1
    if(sock < 0)
    {
        printf("socket error \n");
        goto __exit;
    }

    //服务器IP设置
    server_addr.sin_family = AF_INET; 
    server_addr.sin_addr.s_addr = INADDR_ANY; //任何地址都OK，估计表示是客户机地址
    server_addr.sin_port = htons(LOCAL_PORT);
    memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
    
    // 服务器绑定套接字与网卡信息
    if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
    {
        printf("Unable to bind\n");
        goto __exit;
    }
    
    // 让服务器进入到监听状态，请求队列最多5个
    if (listen(sock, 5) == -1)
    {
        printf("Listen error\n");
        goto __exit;
    }
    while(1)
    {
        sin_size = sizeof(struct sockaddr_in);
        // 与远端IP地址端口号进行绑定，进行握手，建立新的TCP连接
        connected = accept(sock, (struct sockaddr *)&client_addr, &sin_size);
        printf("new client connected from (%s, %d)\n",inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
        {
            int flag = 1;
            // 设置套接字的一些选项
            setsockopt(connected,
                        IPPROTO_TCP,    // 选择TCP层
                        TCP_NODELAY,    // 不使用NAGLE算法
                        (void *) &flag, /* the cast is historical cruft */
                        sizeof(int)); /* length of option value */
        }
        while(1)
        {
            // 从 Socket中接收数据，它可以是TCP协议簇和UDP协议簇
            recv_data_len = recv(connected, recv_data, RECV_DATA, 0);
            // 错误接收
            if (recv_data_len <= 0)
                break;
            printf("recv %d len data\n",recv_data_len);
            //传输数据
            write(connected,recv_data,recv_data_len); 
        }

        if (connected >= 0)
            closesocket(connected);
        connected = -1;

    }
__exit:
    if (sock >= 0) closesocket(sock);// 关闭套接字
    if (recv_data) free(recv_data);//释放内存
}
void tcpecho_init(void)
{
    //创建内存
    sys_thread_new("tcpecho_thread",tcpecho_thread,NULL,512,4);
}

